package bairui.international.weixin.portal.miniapp.util;

import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.elasticsearch.action.DocWriteRequest.OpType;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;

import com.sh_lianjing.json.jackson.exception.ConvertToJsonStringException;

import bairui.international.model.domain.jpa.TB_City;
import bairui.international.model.domain.jpa.TB_Province;
import bairui.international.model.domain.jpa.TB_Town;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

public class ElasticSearchDeal {

	private static String index = "town";
	
	static void indexDeal(RestHighLevelClient client, List<TB_Town> datas) throws IOException{
		//
    	BulkRequest bulkRequest = new BulkRequest();
    	/*
    	 * 第一步：重建索引
    	 */
    	// 判断索引是否存在
    	boolean hasPumpIndex = client
    		.indices()
    		.exists(
				new GetIndexRequest(index), 
				RequestOptions.DEFAULT
    		);
    	// 删除索引
    	if(hasPumpIndex){
    		client
	    		.indices()
	    		.delete(
					new DeleteIndexRequest(index),
					RequestOptions.DEFAULT
				);
    	}
    	// 创建索引
    	CreateIndexResponse createIndexResponse = client
    		.indices()
    		.create(
				new CreateIndexRequest(index)
					.source(CreateIndexData, XContentType.JSON),
				RequestOptions.DEFAULT
			);
    	if(!createIndexResponse.isAcknowledged()){
    		throw new RuntimeException("acknowledged: false");
    	}
    	if(!createIndexResponse.isShardsAcknowledged()){
    		throw new RuntimeException("shards_acknowledged: false");
    	}
//    	/*
//    	 * 清空数据
//    	 */
//    	BulkByScrollResponse deleteResult = client
//    		.deleteByQuery(
//				new DeleteByQueryRequest(index)
//	    			.setQuery(QueryBuilders.matchAllQuery()), 
//				RequestOptions.DEFAULT
//    		);
//    	deleteResult.getSearchFailures().forEach(it->{throw new RuntimeException(it.getReason());});
//    	deleteResult.getBulkFailures().forEach(it->{throw new RuntimeException(it.getCause());});
    	/*
    	 * 第二步：批量添加数据
    	 */
    	for(TB_Town data : datas){
    		bulkRequest
    			.add(
    				new IndexRequest(index)
	    	            .id(data.getId().toString())
	    	            .opType(OpType.CREATE)
	    	            .source(
	    	            	getData(data)
	    	            )
    			);
    	}
    	// 同步执行批处理
		BulkResponse r = client.bulk(bulkRequest, RequestOptions.DEFAULT);
		if (r.hasFailures()) {
			throw new RuntimeException(r.buildFailureMessage());
		}
	}
	
	/**
	 * 创建索引数据
	 */
	private static String CreateIndexData = "{	\n" + 
	"	   \"settings\": {						\n" +
	"        \"index\": {						\n" +
	"            \"number_of_shards\": \"1\",	\n" +
	"            \"number_of_replicas\": \"0\"	\n" +
	"        },									\n" +
	"        \"analysis\": {					\n" +
	"            \"normalizer\": {				\n" +
	"                \"my_normalizer\": {		\n" +
	"                    \"type\": \"custom\",	\n" +
	"                    \"char_filter\": [],	\n" +
	"                    \"filter\": [			\n" +
	"                        \"lowercase\",		\n" +
	"                        \"asciifolding\"	\n" +
	"                    ]						\n" +
	"                }							\n" +
	"            }								\n" +
	"        }									\n" +
	"    },										\n" +
	"    \"mappings\": {						\n" +
	"        \"properties\": {					\n" +
	"            \""+Field.Id+"\": {					\n" +
	"                \"type\": \"long\"			\n" +
	"            },								\n" +
	"            \""+Field.Name+"\": {					\n" +
	"                \"type\": \"keyword\",		\n" +
	"                \"normalizer\": \"my_normalizer\"\n" +
	"            },								\n" +
	"            \""+Field.CityId+"\": {				\n" +
	"                \"type\": \"long\"			\n" +
	"            },								\n" +
	"            \""+Field.CityName+"\": {				\n" +
	"                \"type\": \"keyword\",		\n" +
	"                \"normalizer\": \"my_normalizer\"\n" +
	"            },								\n" +
	"            \""+Field.ProvinceId+"\": {			\n" +
	"                \"type\": \"long\"			\n" +
	"            },								\n" +
	"            \""+Field.ProvinceName+"\": {			\n" +
	"                \"type\": \"keyword\",		\n" +
	"                \"normalizer\": \"my_normalizer\"\n" +
	"            },								\n" +
	"            \""+Field.Search+"\": {				\n" +
	"                \"type\": \"keyword\",		\n" +
	"                \"normalizer\": \"my_normalizer\"\n" +
	"            },								\n" +
	"            \""+Field.OrderValue+"\": {			\n" +
	"                \"type\": \"integer\"		\n" +
	"            }								\n" +
	"        }									\n" +
	"    }										\n" +
	"}";
	
	private static XContentBuilder getData(TB_Town data) throws IOException{
		String name = data.getName();
		TB_City city = data.getCity();
		TB_Province province = city.getProvince();
		String cityName = city.getName();
		String provinceName = province.getName();
		return XContentFactory.jsonBuilder()
			.startObject()
			.field(Field.Id, data.getId())
			.field(Field.Name, name)
			.field(Field.CityId, city.getId())
			.field(Field.CityName, cityName)
			.field(Field.ProvinceId, province.getId())
			.field(Field.ProvinceName, provinceName)
			.field(Field.OrderValue, data.getOrderValue())
			.field(Field.Search, provinceName + " " + cityName + " " + name)
			.endObject();
	}
	
	/**
	 * 查询
	 */
	public static Output query(RestHighLevelClient client, Consumer<BoolQueryBuilder> where, Page page, Sort sort) throws IOException, ConvertToJsonStringException{
		// 查询
		SearchSourceBuilder query = new SearchSourceBuilder();
			BoolQueryBuilder booleanBuilder = QueryBuilders.boolQuery();
			// 设置条件
			where.accept(booleanBuilder);
//			for(String para : params){
//				booleanBuilder
//					.must(QueryBuilders.wildcardQuery("name", "*" + para.trim() + "*"));
//			}
			query
				.query(booleanBuilder)
				.from(page.getStart())
				.size(page.getSize())
				.sort(sort.getFieldName(), sort.getOrder());
		//
		SearchResponse response = client.search(
				new SearchRequest(index)
					.source(query), 
				RequestOptions.DEFAULT
			);
		// 返回数据
		List<OutputRecord> records = Stream
			.of(response.getHits().getHits())
			.map(it->{
				return new OutputRecord(
						(int)it.getSourceAsMap().get(Field.Id),
						(String)it.getSourceAsMap().get(Field.Name),
						(int)it.getSourceAsMap().get(Field.CityId),
						(String)it.getSourceAsMap().get(Field.CityName),
						(int)it.getSourceAsMap().get(Field.ProvinceId),
						(String)it.getSourceAsMap().get(Field.ProvinceName)
					);
			})
			.collect(Collectors.toList());
		return new Output(records, records.size(), response.getHits().getTotalHits().value);
	}
	
	@AllArgsConstructor
	public static class Page{
		@Getter private int start;
		@Getter private int size;
	}
	
	@AllArgsConstructor
	public static class Sort{
		@Getter private String fieldName;
		@Getter private SortOrder order;
	}
	
	@RequiredArgsConstructor
	public static class OutputRecord {
		@Getter private final int id;
		@Getter private final String name;
		@Getter private final int cityId;
		@Getter private final String cityName;
		@Getter private final int provinceId;
		@Getter private final String provinceName;
	}
	
	@RequiredArgsConstructor
	public static class Output {
		@Getter private final List<OutputRecord> records;
		@Getter private final int size;
		@Getter private final long total;
	}
	
	/**
	 * Field 成员
	 *
	 */
	public static class Field {
		public static final String Search 		= "search";
		public static final String Id 			= "id";
		public static final String Name 		= "name";
		public static final String CityId		= "cityId";
		public static final String CityName		= "cityName";
		public static final String ProvinceId 	= "provinceId";
		public static final String ProvinceName = "provinceName";
		public static final String OrderValue 	= "orderValue";
	}
	
//	/**
//	 * 添加
//	 */
//	public static void add(RestHighLevelClient client, TB_Pump pump) throws IOException{
//		 // 插入数据
//	     client
//	       .index(
//	          new IndexRequest("pump")
//	            .id(pump.getId().toString())
//	            .opType(OpType.CREATE)
//	            .source(
//	            	getData(pump)
//	            ),
//	          RequestOptions.DEFAULT
//	       );
//	}
//	
//	/**
//	 * 编辑
//	 */
//	public static void edit(RestHighLevelClient client, TB_Pump pump) throws IOException{
//		client
//	       .update(
//	         new UpdateRequest("pump", pump.getId().toString())
//	            .doc(
//            		getData(pump)
//	            ),
//	         RequestOptions.DEFAULT
//	       );
//	}
//	
//	/**
//	 * 删除
//	 */
//	public static void delete(RestHighLevelClient client, Long id) throws IOException{
//		client
//	       .delete(
//	          new DeleteRequest("pump", id.toString()),
//	          RequestOptions.DEFAULT
//	       );
//	}
	
}
